ggplot2A universal framework that allows creating and combining without limits.
Almost.
Coordinates Geometries Scales Theme
Data Mapping Statistics Facets
dplyr/tidyr)ggplot2Multiplex CRISPR editing of wood for sustainable fiber production. Sulis DB, […], Barrangou R, Wang JP. 2023. Science 381:216–221. 10.1126/science.add4514
Three panels from main figure 3.
Assign the function output of read_tsv()
to the object sulis_bar_data.
# A tibble: 18 × 4
line replicate lignin CL
<chr> <dbl> <dbl> <dbl>
1 H-4 1 15.5 4.03
2 H-4 2 16.1 3.75
3 I-18 1 17.9 2.89
4 I-18 2 19.5 2.78
5 I-18 3 22.0 2.92
6 J-25 1 18.6 3.92
7 J-25 2 20.7 3.27
8 K-6 1 12.1 5.97
9 K-6 2 11.4 6.61
10 K-9 1 23.0 2.95
11 K-9 2 22.6 2.97
12 K-9 3 20.9 3.18
13 K-13 1 22.2 3.04
14 K-13 2 23.0 2.83
15 K-13 3 23.5 2.65
16 Wildtype 1 22.1 2.85
17 Wildtype 2 23.7 2.63
18 Wildtype 3 23.5 2.80
Figure from the paper.
Our first ggplot.
Which differences can you spot?
Layers are drawn in order, so before = below
Let’s not do that.
That didn’t work because the bar height is calculated within the function
after_stat(y) tells the function to use the y variable after calculation of the stats (in this case the mean)
library(ggtext)
panel_E <- ggplot(
data = sulis_bar_data,
aes(
x = fct_reorder(
line,
lignin,
.desc = TRUE
),
y = lignin
)
) +
scale_fill_distiller(
palette = "Greys"
) +
geom_bar(
aes(fill = after_stat(y)),
stat = "summary",
fun = "mean",
colour = "black"
) +
geom_jitter(width = 0.1) +
labs(
x = NULL,
y = "<b>Lignin content</b> (% wt)"
) +
theme(
axis.title.y = element_markdown()
)
panel_Eggtext is a ggplot2 extension that implements HTML and markdown syntax within strings
panel_E <- ggplot(
data = sulis_bar_data,
aes(
x = fct_reorder(
line,
lignin,
.desc = TRUE
),
y = lignin
)
) +
scale_fill_distiller(
palette = "Greys"
) +
geom_bar(
aes(fill = ..y..),
stat = "summary",
fun = "mean",
colour = "black"
) +
geom_jitter(width = 0.1) +
labs(
x = NULL,
y = "<b>Lignin content</b> (% wt)"
) +
theme(
axis.title.y = element_markdown(),
axis.text.x = element_text(
angle = 90,
vjust = 0.5,
hjust = 1
)
)
panel_Epanel_E <- ggplot(
data = sulis_bar_data,
aes(
x = fct_reorder(
line,
lignin,
.desc = TRUE
),
y = lignin
)
) +
scale_fill_distiller(
palette = "Greys"
) +
geom_bar(
aes(fill = ..y..),
stat = "summary",
fun = "mean",
colour = "black"
) +
geom_jitter(width = 0.1) +
labs(
x = NULL,
y = "<b>Lignin content</b> (% wt)"
) +
theme(
axis.title.y = element_markdown(),
axis.text.x = element_text(
angle = 90,
vjust = 0.5,
hjust = 1
),
legend.position = "none"
)
panel_Epanel_E <- ggplot(
data = sulis_bar_data,
aes(
x = fct_reorder(
line,
lignin,
.desc = TRUE
),
y = lignin
)
) +
scale_fill_distiller(
palette = "Greys"
) +
geom_bar(
aes(fill = ..y..),
stat = "summary",
fun = "mean",
colour = "black",
width = 0.8
) +
geom_jitter(
width = 0.1,
shape = 21,
fill = "black",
colour = "white"
) +
labs(
x = NULL,
y = "<b>Lignin content</b> (% wt)"
) +
scale_y_continuous(
expand = expansion(
mult = c(0, 0.05)
)
) +
theme_sulis() +
theme(
axis.title.y = element_markdown(),
axis.text.x = element_text(
angle = 90,
vjust = 0.5,
hjust = 1
),
legend.position = "none"
)
panel_EApplying a theme_*() can completely change the look — see how to make your own in the exercise file
Figure from the paper.
Our first ggplot. Text for ants? We’ll fix that later.
Which layers and functions need changing?
panel_F <- ggplot(
data = sulis_bar_data,
aes(
x = fct_reorder(
line,
lignin,
.desc = TRUE
),
y = CL
)
) +
scale_fill_distiller(
palette = "Greys",
direction = 1
) +
geom_bar(
aes(fill = ..y..),
stat = "summary",
fun = "mean",
colour = "black",
width = 0.8
) +
geom_jitter(
width = 0.1,
shape = 21,
fill = "black",
colour = "white"
) +
labs(
x = NULL,
y = "<b>C/L ratio</b>"
) +
scale_y_continuous(
expand = expansion(
mult = c(0, 0.05)
)
) +
theme_sulis() +
theme(
axis.title.y = element_markdown(),
axis.text.x = element_text(
angle = 90,
vjust = 0.5,
hjust = 1
),
legend.position = "none"
)
panel_FThree panels from main figure 3.
panel_K <- ggplot(
data = sulis_scatter_data,
aes(
x = rel_lignin,
y = rel_volume
)
) +
geom_point(
aes(
colour = type,
fill = after_scale(
alpha(colour, 0.4)
)
),
shape = "circle filled"
) +
scale_colour_manual(
values = c("#275d95", "#d25952")
) +
theme_sulis() +
theme(
legend.position = c(0.25, 0.95),
legend.title = element_blank()
)
panel_Kpanel_K <- ggplot(
data = sulis_scatter_data,
aes(
x = rel_lignin,
y = rel_volume
)
) +
geom_hline(
yintercept = 100,
colour = "grey",
linetype = "dashed"
) +
geom_point(
aes(
colour = type,
fill = after_scale(alpha(colour, 0.4))
),
shape = "circle filled"
) +
scale_colour_manual(
values = c("#275d95", "#d25952")
) +
theme_sulis() +
theme(
legend.position = c(0.25, 0.95),
legend.title = element_blank()
)
panel_K Figure from the paper.
Our third ggplot.
Where do the lines shown in E and F fall in K?
# A tibble: 13 × 7
line replicate type label rel_lignin rel_CL rel_volume
<chr> <dbl> <chr> <chr> <dbl> <dbl> <dbl>
1 WT 1 Wildtype <NA> 103. 97.2 89.6
2 WT 2 Wildtype <NA> 99.6 100. 98.6
3 WT 3 Wildtype <NA> 97.9 102. 113.
4 H-4 1 CRISPR-edited lines H-4-1 67.0 146. 106.
5 H-4 2 CRISPR-edited lines H-4-2 69.9 136. 66.2
6 H-18 1 CRISPR-edited lines <NA> 70.8 150. 72.6
7 H-19 1 CRISPR-edited lines <NA> 89.3 105. 85.6
8 H-19 2 CRISPR-edited lines <NA> 87.6 101. 103.
9 H-19 3 CRISPR-edited lines <NA> 79.3 117. 63.2
10 H-19 4 CRISPR-edited lines <NA> 98.8 99.1 52.1
11 H-20 1 CRISPR-edited lines <NA> 95.5 111. 95.0
12 H-20 2 CRISPR-edited lines <NA> 79.8 128. 92.5
13 H-20 3 CRISPR-edited lines <NA> 85.3 130. 75.9
library(ggrepel)
panel_K <- ggplot(
data = sulis_scatter_data,
aes(
x = rel_lignin,
y = rel_volume
)
) +
geom_hline(
yintercept = 100,
colour = "grey",
linetype = "dashed"
) +
geom_point(
aes(
colour = type,
fill = after_scale(alpha(colour, 0.4))
),
shape = "circle filled"
) +
geom_label_repel(
aes(label = label),
) +
scale_colour_manual(
values = c("#275d95", "#d25952")
) +
labs(
x = "**Lignin content** (% of wildtype)",
y = "<b>Stem volume</b> (% of wildtype)"
) +
theme_sulis() +
theme(
axis.title.x = element_markdown(),
axis.title.y = element_markdown(),
legend.position = c(0.25, 0.95),
legend.title = element_blank()
)
panel_Kggrepel creates labels that automatically avoid overlapping
library(ggrepel)
panel_K <- ggplot(
data = sulis_scatter_data,
aes(
x = rel_lignin,
y = rel_volume
)
) +
geom_hline(
yintercept = 100,
colour = "grey",
linetype = "dashed"
) +
geom_point(
aes(
colour = type,
fill = after_scale(alpha(colour, 0.4))
),
shape = "circle filled"
) +
geom_label_repel(
aes(label = label),
size = 8
) +
scale_colour_manual(
values = c("#275d95", "#d25952")
) +
labs(
x = "**Lignin content** (% of wildtype)",
y = "<b>Stem volume</b> (% of wildtype)"
) +
theme_sulis() +
theme(
axis.title.x = element_markdown(),
axis.title.y = element_markdown(),
legend.position = c(0.25, 0.95),
legend.title = element_blank()
)
panel_KGeom_* size is defined in mm, theme elements in pt
ggtext_size <- 8 / (14 / 5)
library(ggrepel)
panel_K <- ggplot(
data = sulis_scatter_data,
aes(
x = rel_lignin,
y = rel_volume
)
) +
geom_hline(
yintercept = 100,
colour = "grey",
linetype = "dashed"
) +
geom_point(
aes(
colour = type,
fill = after_scale(alpha(colour, 0.4))
),
shape = "circle filled"
) +
geom_label_repel(
aes(label = label),
size = ggtext_size
) +
scale_colour_manual(
values = c("#275d95", "#d25952")
) +
labs(
x = "**Lignin content** (% of wildtype)",
y = "<b>Stem volume</b> (% of wildtype)"
) +
theme_sulis() +
theme(
axis.title.x = element_markdown(),
axis.title.y = element_markdown(),
legend.position = c(0.25, 0.95),
legend.title = element_blank()
)
panel_K14 to 5 is the ratio of pt to mm
ggtext_size <- 8 / (14 / 5)
library(ggrepel)
panel_K <- ggplot(
data = sulis_scatter_data,
aes(
x = rel_lignin,
y = rel_volume
)
) +
geom_hline(
yintercept = 100,
colour = "grey",
linetype = "dashed"
) +
geom_point(
aes(
colour = type,
fill = after_scale(alpha(colour, 0.4))
),
shape = "circle filled"
) +
geom_label_repel(
aes(label = label),
size = ggtext_size,
label.size = NA,
fill = rgb(1, 1, 1, 0.5),
min.segment.length = 0
) +
scale_colour_manual(
values = c("#275d95", "#d25952")
) +
labs(
x = "**Lignin content** (% of wildtype)",
y = "<b>Stem volume</b> (% of wildtype)"
) +
theme_sulis() +
theme(
axis.title.x = element_markdown(),
axis.title.y = element_markdown(),
legend.position = c(0.25, 0.95),
legend.title = element_blank()
)
panel_Kpatchwork automatically aligns plots into multi-panel figures
PDFs don’t lose resolution and are easily edited in Inkscape/Photoshop
ragg and its devices (agg_tiff, agg_jpeg, agg_png) improve raster graphics text rendering
Open up 2023_ggplot2_exercises.rmd and give it a try